/**
 * ComponentVisitor.java
 * @author: liuex
 * 2008-1-7 ����05:38:40
 *
 * note: 
 */
package org.lex.awt;

import java.awt.Component;
import java.awt.Container;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

import org.lex.filter.Filter;
import org.lex.filter.Filters;
import org.lex.utils.functor.UnaryFunctor;
import org.lex.utils.tree.AbstractNode;
import org.lex.utils.tree.BFS;


public class ComponentVisitor {
	public static <T extends UnaryFunctor<?, Component>> void bfs(Component root, T processor) {
		if (null == root) {
			return;
		} else if (false == root instanceof Container) {
			processor.operate(root);
			return;
		} else {
			Queue<Container> queue = new LinkedList<Container>();
			queue.offer((Container) root);
			while (false == queue.isEmpty()) {
				Container top = queue.poll();
				for (Component child : top.getComponents())
					if (child instanceof Container)
						queue.offer((Container) child);
					else
						processor.operate(child);
				processor.operate(top);
			}
		}
	}

	public static Iterator<Component> bfs(Component root) {
		return new BFS<Component>(new ComponentNode(root));
	}

	public static <T extends UnaryFunctor<?, Component>> void previsite(Component root, T processor) {
		previsite(root, Filters.<Component> acceptAllFilter(), processor);
	}

	/**
	 * ǰ�����
	 * 
	 * @param <T>
	 * @param root
	 * @param filter
	 * @param processor
	 */
	public static <T extends UnaryFunctor<?, Component>> void previsite(Component root, Filter<Component> filter, T processor) {
		if (false == root instanceof Container) {
			if (true == filter.accept(root))
				processor.operate(root);
			return;
		}
		Stack<Container> stack = new Stack<Container>();
		stack.push((Container) root);
		while (false == stack.empty()) {
			Container tmp = stack.pop();
			if (true == filter.accept(tmp))
				processor.operate(tmp);
			Component[] children = tmp.getComponents();
			if (null == children)
				continue;
			for (Component c : children) {
				if (true == filter.accept(c))
					processor.operate(c);
				if (c instanceof Container)
					stack.push((Container) c);
			}
		}
	}

	static class ComponentNode extends AbstractNode {
		private static final ComponentNode[] EMPTY = new ComponentNode[0];
		private ComponentNode[] children = null;

		public ComponentNode(Component data) {
			super(data);
		}

		@Override
		public Component getData() {
			return (Component) super.getData();
		}

		@Override
		public ComponentNode getChildAt(int index) {
			if (null == children)
				children = this.getChildren();
			return children[index];
		}

		@Override
		public int getChildCount() {
			if (null == children)
				children = this.getChildren();
			return children.length;
		}

		private ComponentNode[] getChildren() {
			if (super.getData() instanceof Container) {
				Component[] components = ((Container) super.getData()).getComponents();
				ComponentNode[] nodes = new ComponentNode[components.length];
				for (int i = 0; i < nodes.length; i++)
					nodes[i] = new ComponentNode(components[i]);
				return nodes;
			} else
				return EMPTY;
		}
	}

	private ComponentVisitor() {
	}
}
